#!/usr/bin/env perl
# $Id: check_bgp.pl 9c2bfe7e5835 2012/12/03 06:37:29 pgurumur $
# Copyright (c) 2009 Prabhu Gurumurthy <pgurumur@gmail.com>
# 
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
# 
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# __version__  = "$Revision: 9c2bfe7e5835 $"
# __author__   = "$Author: pgurumur $"
# __modified__ = "$Date: 2012-12-03 06:37:29Z $"
#
use strict;
use warnings;
use SNMP;
use Getopt::Long;
use Net::DNS;

Getopt::Long::Configure("default", "bundling");
push my @prog, split(/\//, $0);
my $program = $prog[$#prog];

my $arg = int(scalar(@ARGV));
my %options = ();
my $hostname = undef;
my $timeout = 30;

my %ERRORS = (
   -1 => 'UNKNOWN',
   0  => 'OK',
   1  => 'WARNING',
   2  => 'CRITICAL', 
);

my %PEERSTATE = (
   1 => 'idle',
   2 => 'connect',
   3 => 'active',
   4 => 'opensent',
   5 => 'openconfirm',
   6 => 'established',
   7 => 'established' # JunOS bug
);

my $bgpPeerState = '1.3.6.1.2.1.15.3.1.2';
my $bgpPeerRemoteAs = '1.3.6.1.2.1.15.3.1.9';

sub main {
   GetOptions(\%options, "help|?", "hostname|H=s", "address|a=s", "comm|c=s",
      "version|v=s") or usage();
   usage() if $options{help};
   my $address = undef;

   if (!defined($options{version})) {
      $options{version} = 2;
   }

   if ($options{hostname} && $options{comm}) {
      $SIG{INT} = \&sighandle;
      $SIG{TERM} = \&sighandle;

      my $result = gethostbyname($options{hostname});
      $hostname = $options{hostname};
      if ($result) {
         my $session = new SNMP::Session(
            DestHost       => $options{hostname},
            Community      => $options{comm},
            Version        => $options{version},
         );

         unless ($session) {
            errx(-1, "SNMP connection failed to $options{hostname}");
         }

         push my @varlist, [$bgpPeerState, $options{address}];
         push @varlist, [$bgpPeerRemoteAs, $options{address}];

         my $vars = new SNMP::VarList(@varlist);
         my ($stateval, $as) = $session->get($vars);
         my $bgpState = undef;
         my $asinfo = getasinfo($as);

         if ($stateval) {
            $bgpState = $PEERSTATE{$stateval};
         }
         else {
            errx(-1, "peer $options{address} not in $hostname BGP table");
         }

         if (defined($bgpState)) {
            if ($bgpState eq 'established') {
               errx(0, "ASN $as ($asinfo ) is $bgpState state");
            }
            else {
               errx(2, "ASN $as ($asinfo ) is $bgpState state");
            }
         }
         else {
            errx(-1, "peer $options{address} not in $hostname BGP table");
         }
      }
   }
   else {
      usage();
   }
}

sub usage {
   printf("%s options\n", $program);
   printf("options: \n");
   printf("\t-H | --hostname  [ hostname of the router ]\n");
   printf("\t-a | --address   [ BGP peer remote address (Not peer id)]\n");
   printf("\t-c | --comm      [ SNMP community (default: public)]\n");
   printf("\t-v | --version   [ SNMP version (default: 1)]\n");
   printf("\t-h | --help      [ prints this help ]\n");
   printf("\n");
   printf("usage: %s -H <router> -a <peer_address> -c <community> -v <1|2>\n",
      $program);
   printf("\n");
   exit 1;
}

sub errx {
   my ($state, $message) = @_;

   printf("%s: %s\n", $ERRORS{$state}, $message);
   exit($state);
}

sub getasinfo {
   my $as = shift;
   my $retval = undef;

   my $res   = Net::DNS::Resolver->new;
   my $asn = sprintf("AS%s.asn.cymru.com", $as);
   my $query = $res->query($asn, "TXT");
   
   if ($query) {
      foreach my $rr (grep { $_->type eq 'TXT' } $query->answer) {
         push my @data, split(/\|/, $rr->txtdata);
         chomp($data[$#data]);
         $retval = $data[$#data];
      }
   }

   return $retval;
}

sub sighandle {
   my ($signal) = @_;
   printf("%s got signal %d, terminating the application\n", $signal);
   exit(1);
}

$SIG{'ALRM'} = sub {
   printf("ERROR: No response from %s (alarm)\n", $hostname);
   exit $ERRORS{"UNKNOWN"};
};
alarm($timeout);

if ($arg < 1) {
   usage();
}
else {
   main();
}
